package main

import (
	"bufio"
	"bytes"
	"crypto/sha256"
	"database/sql"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/chengjoey/web-terminal/views"
	"github.com/gin-gonic/gin"
	"github.com/go-ini/ini"
	_ "github.com/go-sql-driver/mysql"
	"github.com/tjfoc/gmsm/sm4"
	"html/template"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"
)



var (
	//EnvGOPATH     = os.Getenv("GOPATH")
	TemplateFiles = fmt.Sprintf("%s/templates/*.html","./")
	StaticFiles   = fmt.Sprintf("%s/templates/static", "./")
)

//对产生的任何error进行处理
func JSONAppErrorReporter() gin.HandlerFunc {
	return jsonAppErrorReporterT(gin.ErrorTypeAny)
}

func jsonAppErrorReporterT(errType gin.ErrorType) gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Next()
		detectedErrors := c.Errors.ByType(errType)
		if len(detectedErrors) > 0 {
			err := detectedErrors[0].Err
			var parsedError *views.ApiError
			switch err.(type) {
			//如果产生的error是自定义的结构体,转换error,返回自定义的code和msg
			case *views.ApiError:
				parsedError = err.(*views.ApiError)
			default:
				parsedError = &views.ApiError{
					Code:    http.StatusInternalServerError,
					Message: err.Error(),
				}
			}
			c.IndentedJSON(parsedError.Code, parsedError)
			return
		}

	}
}

//设置所有跨域请求
func CORSMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
		c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")

		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(204)
			return
		}

		c.Next()
	}
}


type Setconf struct {
    Ip_file string  `mapstructure:"Ipfile" json:"Ipfile" ini:"Ipfile"`
	Qy_rebootKey string  `mapstructure:"Qy_rebootKey" json:"Qy_rebootKey" ini:"Qy_rebootKey"`
	CheckserverTime int  `mapstructure:"CheckserverTime" json:"CheckserverTime" ini:"CheckserverTime"`
	Cmem float32  `mapstructure:"cmem" json:"cmem" ini:"cmem"`
	Ccpu float64  `mapstructure:"ccpu" json:"ccpu" ini:"ccpu"`
	ConectKey string  `mapstructure:"ConectKey" json:"ConectKey" ini:"ConectKey"`
	CorncmdbupdateTime int  `mapstructure:"CorncmdbupdateTime" json:"CorncmdbupdateTime" ini:"CorncmdbupdateTime"`
	Startport  string  `mapstructure:"Startport" json:"Startport" ini:"Startport"`
	Apiserver  string  `mapstructure:"Apiserver" json:"Apiserver" ini:"Apiserver"`
	Apiport  string  `mapstructure:"Apiport" json:"Apiport" ini:"Apiport"`
	Ansible_api  string  `mapstructure:"Ansible_api" json:"Ansible_api" ini:"Ansible_api"`
	Ansible_mod  string  `mapstructure:"Ansible_mod" json:"Ansible_mod" ini:"Ansible_mod"`
	BlackTime  int  `mapstructure:"BlackTime" json:"BlackTime" ini:"BlackTime"`
	ChecklistenPs_time  int  `mapstructure:"ChecklistenPs_time" json:"ChecklistenPs_time" ini:"ChecklistenPs_time"`
	CheckserverTimeout  int  `mapstructure:"CheckserverTimeout" json:"CheckserverTimeout" ini:"CheckserverTimeout"`
	ChecklistenTimeout  int  `mapstructure:"ChecklistenTimeout" json:"ChecklistenTimeout" ini:"ChecklistenTimeout"`
	Qy_rebootswitch  string  `mapstructure:"Qy_rebootswitch" json:"Qy_rebootswitch" ini:"Qy_rebootswitch"`
	User  string  `mapstructure:"User" json:"User" ini:"User"`
	Passwd  string  `mapstructure:"Passwd" json:"Passwd" ini:"Passwd"`
	Dbaddress string  `mapstructure:"Dbaddress" json:"Dbaddress" ini:"Dbaddress"`
}

type Config struct {
	Setconf Setconf `json:"setconf" ini:"setconf"`
}

var (
	CONFIG = new(Config)
)

func InitConfigFromIni() {
	err := ini.MapTo(CONFIG, "./conf.ini")
	if err != nil {
		log.Println(err)
		return
	}
}

//结构体区
var servermap map[string]string
var server_diable_map map[string]string
var cmdbmap map[string]string
var checking map[string]string


type Order struct{
	Errmsg string  `json:"errmsg"`
	Goods []Good `json:"good"`
}

type Good struct{
	GoodsName string `json:"goods_name"`
	Goodsstatus string `json:"goods_status"`
}

type Order2 struct{
	Errmsg string  `json:"errmsg"`
	Goods []Good2 `json:"good"`
}

type Good2 struct {
	GoodsName string `json:"goods_name"`
	Hostname  string `json:"Hostname"`
	Core    int    `json:"core"`
	Cpuname string `json:"cpuname"`
	TotalMem string `json:"total_mem"`
	Platform        string `json:"platform"`
	PlatformVersion string `json:"PlatformVersion"`
	Os              string `json:"Os"`
	KernelVersion   string `json:"KernelVersion"`
	Status          string `json:"status"`
}



type cpuinfos struct {
	Cpuload  float64 `json:"cpuload"`
}

type meminfos struct {
	Total int `json:"total"`
	Available int `json:"available"`
	Used int `json:"used"`
	UsedPercent float64 `json:"usedPercent"`
	Free int `json:"free"`
	Active int `json:"active"`
	Inactive int `json:"inactive"`
	Wired int `json:"wired"`
	Laundry int `json:"laundry"`
	Buffers int `json:"buffers"`
	Cached int `json:"cached"`
	Writeback int `json:"writeback"`
	Dirty int `json:"dirty"`
	Writebacktmp int `json:"writebacktmp"`
	Shared int `json:"shared"`
	Slab int `json:"slab"`
	Sreclaimable int `json:"sreclaimable"`
	Sunreclaim int `json:"sunreclaim"`
	Pagetables int `json:"pagetables"`
	Swapcached int `json:"swapcached"`
	Commitlimit int `json:"commitlimit"`
	Committedas int `json:"committedas"`
	Hightotal int `json:"hightotal"`
	Highfree int `json:"highfree"`
	Lowtotal int `json:"lowtotal"`
	Lowfree int `json:"lowfree"`
	Swaptotal int `json:"swaptotal"`
	Swapfree int `json:"swapfree"`
	Mapped int `json:"mapped"`
	Vmalloctotal int64 `json:"vmalloctotal"`
	Vmallocused int `json:"vmallocused"`
	Vmallocchunk int64 `json:"vmallocchunk"`
	Hugepagestotal int `json:"hugepagestotal"`
	Hugepagesfree int `json:"hugepagesfree"`
	Hugepagesize int `json:"hugepagesize"`
}

func webhook(key string,msg string) {

	if CONFIG.Setconf.Qy_rebootswitch == "on" {
		Hookaddress := "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=" + key
		content := `{"msgtype": "text",
      "text": {"content": "` + msg + ` "}
               }`

		content2 := strings.NewReader(content)
		req, err := http.NewRequest("POST", Hookaddress, content2)
		if err != nil {
			fmt.Printf("Error %v", err)
		}
		client := &http.Client{}
		req.Header.Set("Content-Type", "application/json; charset=uft-8")
		resp, err := client.Do(req)
		if err != nil {
			fmt.Printf("ERROR: %v", err)
		}
		defer resp.Body.Close()
	}else {
		fmt.Println("conf load : Qy_rebootswitch is off,Refuse to send Qy")
	}
}

func getinfo(ip string) string {
    url := ip
	method := "GET"
	client := &http.Client {
	}
	req, err := http.NewRequest(method, url, nil)

	if err != nil {
		fmt.Println("1",err)

	}
	res,err := client.Do(req)
	if err != nil {
		runtime.Goexit()
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		fmt.Println("3",err)

	}
  return string(body)
}
func bfb(u int,t int) float32 {
	var i= u
	var j= t
	var sum1 float32
	i1:=float32(i)
	j1:=float32(j)

	sum1=i1/j1
    sum1 = sum1 * 100
	return  sum1

}

func listserver(ip string,port string) (string,float32,float64,string){
	if len(ip) == 0 {
        runtime.Goexit()
	}
	url1 := "http://" + ip  + ":" + port + "/getmem"
	url2 := "http://" + ip  + ":" + port + "/getcpuload"
	x := getinfo(url1)
	x2 := getinfo(url2)
	sendmem := &meminfos{}
	err  := json.Unmarshal([]byte(x),sendmem)
	if err != nil{
		fmt.Println(err)
	}
	total := sendmem.Total
	use := sendmem.Used
    bfb2 := bfb(use,total)



    sendmemcpu := &cpuinfos{}
	err2  := json.Unmarshal([]byte(x2),sendmemcpu)
	if err2 != nil{
		fmt.Println(err2)
	}
	load := sendmemcpu.Cpuload
	if bfb2 > CONFIG.Setconf.Cmem  || load > CONFIG.Setconf.Ccpu {
		status := "Bad"
		fmt.Printf("%s\t  %.3f%%\t   %.2f%%\t           %s\n",ip,bfb2,load,status)
        return  ip,bfb2,load,status
	}else {
		status := "OK"
		fmt.Printf("%s\t  %.3f%%\t   %.2f%%\t           %s\n",ip,bfb2,load,status)
		return  ip,bfb2,load,status
	}
}




func insterdisktotable(ip,diskname,mountpoint,fstype,opts,disk_f,inode_f,disk_t,inode_t,update_time,elseinfo string){
	sqlStr := "INSERT INTO `diskinfo` (`ip`,`disk_name`,`mount_point`,`fstype`,`opts`,`disk_free`,`inode_free`,`disk_total`,`inode_total`,`update_time`,`elseinfo`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
	ret, err := db.Exec(sqlStr,ip,diskname,mountpoint,fstype,opts,disk_f,inode_f,disk_t,inode_t,update_time,elseinfo )
	fmt.Println(ip,diskname,mountpoint,fstype,opts,disk_f,inode_f,disk_t,inode_t,update_time,elseinfo)
	if err != nil {
		fmt.Printf("insert failed, err:%v\n", err)
		return
	}
	_, err = ret.LastInsertId()
	if err != nil {
		fmt.Printf("get lastinsert ID failed, err:%v\n", err)
		return
	}

}



type disk_info_json struct {
	IP         string      `json:"ip"`
	DiskName   string      `json:"disk_name"`
	MountPoint string      `json:"mount_point"`
	Fstype     string      `json:"fstype"`
	Opts       string      `json:"opts"`
	DiskFree   string      `json:"disk_free"`
	InodeFree  string      `json:"inode_free"`
	DiskTotal  string      `json:"disk_total"`
	InodeTotal string      `json:"inode_total"`
	UpdateTime string `json:"update_time"`
	Elseinfo   string `json:"elseinfo"`
}

func selectoneip(query,disk string)(string,string,string,string,string,string,string,string,string,string,string) {
	sqlStr := "select * from diskinfo where ip= ? and disk_name = ?"
	var disk_info_jsons disk_info_json
	// 非常重要：确保QueryRow之后调用Scan方法，否则持有的数据库链接不会被释放
	err := db.QueryRow(sqlStr, query,disk).Scan(&disk_info_jsons.IP,&disk_info_jsons.DiskName,&disk_info_jsons.MountPoint,&disk_info_jsons.Fstype,&disk_info_jsons.Opts,&disk_info_jsons.DiskFree,&disk_info_jsons.InodeFree,&disk_info_jsons.DiskTotal,&disk_info_jsons.InodeTotal,&disk_info_jsons.UpdateTime,&disk_info_jsons.Elseinfo)
	if err != nil {
		fmt.Printf("scan failed, err:%v\n", err)
	}
    return disk_info_jsons.IP,disk_info_jsons.DiskName,disk_info_jsons.MountPoint,disk_info_jsons.Fstype,disk_info_jsons.Opts,disk_info_jsons.DiskFree,disk_info_jsons.InodeFree,disk_info_jsons.DiskTotal,disk_info_jsons.InodeTotal,disk_info_jsons.UpdateTime,disk_info_jsons.Elseinfo
}

func selectallip(ip string) (string,string,string,string,string,string,string,string,string,string,string){

	sqlStr := "select * from diskinfo where ip= ?"
	rows, err := db.Query(sqlStr,ip)
	if err != nil {
		fmt.Printf("query failed, err:%v\n", err)
	}
	// 非常重要：关闭rows释放持有的数据库链接
	defer rows.Close()

	// 循环读取结果集中的数据
	for rows.Next() {
		var disk_info_jsons disk_info_json
		err := rows.Scan(&disk_info_jsons.IP,&disk_info_jsons.DiskName,&disk_info_jsons.MountPoint,&disk_info_jsons.Fstype,&disk_info_jsons.Opts,&disk_info_jsons.DiskFree,&disk_info_jsons.InodeFree,&disk_info_jsons.DiskTotal,&disk_info_jsons.InodeTotal,&disk_info_jsons.UpdateTime,&disk_info_jsons.Elseinfo)
		if err != nil {
			fmt.Printf("scan failed, err:%v\n", err)
		}
		return disk_info_jsons.IP,disk_info_jsons.DiskName,disk_info_jsons.MountPoint,disk_info_jsons.Fstype,disk_info_jsons.Opts,disk_info_jsons.DiskFree,disk_info_jsons.InodeFree,disk_info_jsons.DiskTotal,disk_info_jsons.InodeTotal,disk_info_jsons.UpdateTime,disk_info_jsons.Elseinfo
	}
	return "","","","","","","","","","",""
}

//update diskinfo set str=? where ip = ? and disk_name = ?

func updatediskinfo(sql string,new string,ip string,diskname string) {
	sqlStr := sql
	ret, err := db.Exec(sqlStr, new,ip, diskname)
	if err != nil {
		fmt.Printf("update failed, err:%v\n", err)
		return
	}
	_, err = ret.RowsAffected() // 操作影响的行数
	if err != nil {
		fmt.Printf("get RowsAffected failed, err:%v\n", err)
		return
	}

}

type Diskinfo struct{
	Errmsg string  `json:"errmsg"`
	Disknum int `json:"disknum"`
	Data []Datas `json:"good"`
}

type Datas struct{
	Device     string `json:"device"`
	Mountpoint string `json:"mountpoint"`
	Fstype     string `json:"fstype"`
	Opts       string `json:"opts"`
}

func listendisk(){
	fmt.Println("\nStart mod:listendisk")
	for {
		for ip, v := range servermap {
			if v != "OK" {
				fmt.Println(ip, "Can't do checkdisk")
				continue
			}
			var Diskinfos Diskinfo
			//ip := "192.168.159.145"
			url := "http://" + ip + ":" + CONFIG.Setconf.Startport + "/getdisk"
			info := getinfo(url)
			err := json.Unmarshal([]byte(info), &Diskinfos)
			if err != nil {
				fmt.Println("run listendisk err", err)
			}
			for _, x := range append(Diskinfos.Data, Datas{}) {
				disk_name := x.Device
				if len(disk_name) == 0 {
					continue
				}
				moute_point := x.Mountpoint
				fstype := x.Fstype
				opts := x.Opts
				go listendisk_details(ip, disk_name, moute_point, fstype, opts)
				time.Sleep(time.Millisecond * 200)
			}

		}
		fmt.Println("Disk check done")
		time.Sleep(time.Minute * 3)
	}
}

type diskinfodetails_json struct {
	Path              string  `json:"path"`
	Fstype            string  `json:"fstype"`
	Total             int64   `json:"total"`
	Free              int64   `json:"free"`
	Used              int     `json:"used"`
	UsedPercent       float64 `json:"usedPercent"`
	InodesTotal       int     `json:"inodesTotal"`
	InodesUsed        int     `json:"inodesUsed"`
	InodesFree        int     `json:"inodesFree"`
	InodesUsedPercent float64 `json:"inodesUsedPercent"`
}



func listendisk_details(ip,path,moute,fstype,opts string){
	ch := make(chan struct{}, 1)
	go func() {
		var data diskinfodetails_json
		url := "http://" + ip + ":" + CONFIG.Setconf.Startport + "/getdiskdetails"
		info := diskdetails_get(url, moute)
		err := json.Unmarshal([]byte(info), &data)
		if err != nil {
			fmt.Println("run disk_details err", err)
		}
		disk_free := data.Free
		disk_total := data.Total
		inode_free := data.InodesFree
		inode_total := data.InodesTotal
		disk_frees := strconv.FormatInt(disk_free, 10)
		disk_totals := strconv.FormatInt(disk_total, 10)
		inode_frees := strconv.Itoa(inode_free)
		inode_totals := strconv.Itoa(inode_total)
		IP, DName, _, _, _, _, _, _, _, _, _ := selectoneip(ip, path)
		//fmt.Println(IP, DName, MutPt, Ftype, Opt, DFree, IeFree, DTtal, IeTtal, UpateTme, Elseinfo)
		if len(IP) != 0 && len(DName) != 0 {
			fmt.Println("update:",IP,DName)
			var cstSh, _ = time.LoadLocation("Asia/Shanghai")
			t1 := time.Now().In(cstSh).Format("2006-01-02 15:04:05")
			updatediskinfo("update diskinfo set mount_point=? where ip = ? and disk_name = ?",moute,ip,DName)
			updatediskinfo("update diskinfo set fstype=? where ip = ? and disk_name = ?",fstype,ip,DName)
			updatediskinfo("update diskinfo set opts=? where ip = ? and disk_name = ?",opts,ip,DName)
			updatediskinfo("update diskinfo set disk_free=? where ip = ? and disk_name = ?",disk_frees,ip,DName)
			updatediskinfo("update diskinfo set inode_free=? where ip = ? and disk_name = ?",inode_frees,ip,DName)
			updatediskinfo("update diskinfo set disk_total=? where ip = ? and disk_name = ?",disk_totals,ip,DName)
			updatediskinfo("update diskinfo set inode_total=? where ip = ? and disk_name = ?",inode_totals,ip,DName)
			updatediskinfo("update diskinfo set update_time=? where ip = ? and disk_name = ?",t1,ip,DName)
			updatediskinfo("update diskinfo set elseinfo=? where ip = ? and disk_name = ?","waitcheck",ip,DName)
		} else{
			var cstSh, _ = time.LoadLocation("Asia/Shanghai")
			t1 := time.Now().In(cstSh).Format("2006-01-02 15:04:05")
		insterdisktotable(ip, path, moute, fstype, opts, disk_frees, inode_frees, disk_totals, inode_totals, string(t1), "")
	    }
		ch <- struct{}{}
	}()
	select {
	case <-ch:
	case <-time.After(time.Second *  time.Duration(CONFIG.Setconf.CheckserverTimeout)):
		fmt.Println(ip,"Timeout when get diskdetails")
	}
}

func diskdetails_get(ip,path string) string{
	url := ip
	method := "GET"
	payload := &bytes.Buffer{}
	writer := multipart.NewWriter(payload)
	_ = writer.WriteField("path", path)
	err := writer.Close()
	if err != nil {
		fmt.Println(err)

	}
	client := &http.Client {
	}
	req, err := http.NewRequest(method, url, payload)
	if err != nil {
		fmt.Println(err)

	}
	req.Header.Set("Content-Type", writer.FormDataContentType())
	res, err := client.Do(req)
	if err != nil {
		fmt.Println(err)

	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		fmt.Println(err)
	}
	return  string(body)
}


func checkdiskfrommysql(){
	time.Sleep(time.Minute * 1)
	fmt.Println("Start mod:checkdisk")
    for {
		for ip, _ := range servermap {
			sqlStr := "select * from diskinfo where ip= ?"
			rows, err := db.Query(sqlStr, ip)
			if err != nil {
				fmt.Printf("query failed, err:%v\n", err)
			}
			// 非常重要：关闭rows释放持有的数据库链接
			defer rows.Close()

			// 循环读取结果集中的数据
			for rows.Next() {
				var disk_info_jsons disk_info_json
				err := rows.Scan(&disk_info_jsons.IP, &disk_info_jsons.DiskName, &disk_info_jsons.MountPoint, &disk_info_jsons.Fstype, &disk_info_jsons.Opts, &disk_info_jsons.DiskFree, &disk_info_jsons.InodeFree, &disk_info_jsons.DiskTotal, &disk_info_jsons.InodeTotal, &disk_info_jsons.UpdateTime, &disk_info_jsons.Elseinfo)
				if err != nil {
					fmt.Printf("scan failed, err:%v\n", err)
				}
				path := disk_info_jsons.DiskName
				mount := disk_info_jsons.MountPoint
				disk_free := disk_info_jsons.DiskFree
				disk_total := disk_info_jsons.DiskTotal
				inode_free := disk_info_jsons.InodeFree
				inode_total := disk_info_jsons.InodeTotal
				if len(path) == 0 {
					continue
				}
				fmt.Println(path, mount, disk_free, disk_total, inode_free, inode_total)
				disk_f, _ := strconv.ParseInt(disk_free, 10, 64)
				disk_t, _ := strconv.ParseInt(disk_total, 10, 64)
				disk_u := disk_t - disk_f
				disk_p := bfb(int(disk_u), int(disk_t))

				inode_f, err := strconv.Atoi(inode_free)
				inode_t, err := strconv.Atoi(inode_total)
				inode_u := inode_t - inode_f
				inode_p := bfb(int(inode_u), int(inode_t))

				if disk_p > 50 || inode_p > 50 {
					diskinfo := strconv.FormatFloat(float64(disk_p), 'f', 2, 32)
					info := "IP: " + ip + "Disk: " + diskinfo
					webhook(CONFIG.Setconf.Qy_rebootKey, info)
				} else {
					fmt.Println(ip, path, "ok","[INFO:]","Disk:",disk_p,"Inode:",inode_p)
					var cstSh, _ = time.LoadLocation("Asia/Shanghai")
					t1 := time.Now().In(cstSh).Format("2006-01-02 15:04:05")
					elseinfo := "checked-" + t1
					updatediskinfo("update diskinfo set elseinfo=? where ip = ? and disk_name = ?", elseinfo, ip, path)
				}

			}

		}
		time.Sleep(time.Minute * 3)
	}
}

func getnode(c *gin.Context){
	var lip string
	ch := make(chan struct{}, 1)
	go func() {
		Ip := c.DefaultPostForm("ip", "  ")
		lip = Ip
		Port := c.DefaultPostForm("port", CONFIG.Setconf.Startport)
		fmt.Println("get node:", Ip)
		ip, mem, cpu, status := listserver(Ip, Port)
		c.JSON(200, gin.H{
			"Ip":      ip,
			"Membfb":  mem,
			"Cpuload": cpu,
			"Status":  status,
		})
		ch <- struct{}{}
	}()
select {
case <-ch:
case <-time.After(time.Second *  time.Duration(CONFIG.Setconf.CheckserverTimeout)):
	c.JSON(200, gin.H{
		"Ip":      lip,
		"Membfb":  "none",
		"Cpuload":  "none",
		"Status": "Unknown Status" ,
	})
}
}




func getallnode(c *gin.Context){
	var OrderInfo Order
	key := c.PostForm("ckey")
	if key == CONFIG.Setconf.ConectKey{
		for k,v := range servermap {
			OrderInfo.Errmsg = "001"
			OrderInfo.Goods =append(OrderInfo.Goods,Good{GoodsName:k,Goodsstatus:v})
		}
		out ,_ := json.Marshal(OrderInfo)
        fmt.Println(string(out))
		c.JSON(200,OrderInfo)

	}else {
		c.JSON(200,gin.H{
			"err" : 10080,
			"msg" : "key no right",
		})
	}
}

func cmdblist(c *gin.Context){
	var hs Order2
	key := c.PostForm("ckey")
	if key == CONFIG.Setconf.ConectKey{
		for k,v := range cmdbmap {
			lip := strings.Split(v, ";")
			//localhost.localdomain.cluster.local;centos;linux;3.10.0-1160.53.1.el7.x86_64;7.9.2009;Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz;1;OK
			hostname := lip[0]
			pla := lip[1]
			os := lip[2]
			kernel := lip[3]
			plaversion := lip[4]
			cpuname := lip[5]
			corestring := lip[6]
			coreint, _ := strconv.Atoi(corestring)
			mem := lip[7]
			statusx := lip [8]
			hs.Errmsg = "001"
			hs.Goods = append(hs.Goods, Good2{GoodsName: k, Hostname: hostname, Platform: pla, PlatformVersion: plaversion, Os: os, KernelVersion: kernel, Status: statusx,Cpuname: cpuname,Core:coreint,TotalMem:mem})
		}
				out, _ := json.Marshal(hs)
				fmt.Println(string(out))
				c.JSON(200, hs)

	}else {
		c.JSON(200,gin.H{
			"err" : 10080,
			"msg" : "key no right",
		})
	}
}


func checkcurrent(ip string){
	startTime := time.Now()
	var ipid int
	var mems float32
	var cpus float64
	var statuss string
	for {
		ip, mem, cpu, status := listserver(ip, CONFIG.Setconf.Startport)
		if mem > CONFIG.Setconf.Cmem || cpu > CONFIG.Setconf.Ccpu {
			fmt.Println(ip,mem,cpu,status, "持续监控中 还未恢复")
		}else if ipid >= 3 {
			break
		}else {
			fmt.Println("告警恢复: 等待持续观察")
			ipid ++
		}
		fmt.Println("等待下次检查:")
		time.Sleep(time.Second * 10)
		mems = mem
		cpus = cpu
		statuss = status
	}
	delete(checking,ip)
	mem1 := strconv.FormatFloat(float64(mems),'f',2,32)
	cpu2 := strconv.FormatFloat(cpus, 'f', 2, 64)
	elapsed := time.Since(startTime)
	strKm := fmt.Sprintf("%v", elapsed)

	infos := "IP: " + ip + "\n" + "Mem: " + mem1 + "\n" + "Cpuload: " + cpu2 + "\n" + "Status: " + statuss + "\n" +"备注: " + "告警恢复,持续时间:" + strKm
	webhook(CONFIG.Setconf.Qy_rebootKey,infos)

}



func goruncheck(fromip string){
	ch := make(chan struct{}, 1)
	go func() {
	ip,mem,cpu,status := listserver(fromip,CONFIG.Setconf.Startport)
	_, checkingok := checking [ip]
	if status == "Bad" && !(checkingok) {
		mem1 := strconv.FormatFloat(float64(mem),'f',2,32)
		cpu2 := strconv.FormatFloat(cpu, 'f', 2, 64)
		infos := "IP: " + ip + "\n" + "Mem: " + mem1 + "\n" + "Cpuload: " + cpu2 + "\n" + "Status: " + status + "\n" +"备注: " + "开始实时监控使用率"
		webhook(CONFIG.Setconf.Qy_rebootKey,infos)
		servermap [ip] = status
		checking [ip] = "checking"
		go checkcurrent(ip)
	}else if status == "Bad" && (checkingok) {
		fmt.Println(ip," bad,but checking")
	}else  if status == "OK"{
		fmt.Println(ip,"OK")
	}else {
		fmt.Println(ip,"未知状态")
	}
	    v , ok := servermap [ fromip]
		if (ok) && v == "disable" {
			infos := "IP: " + fromip + "\n" + "Status: " + "Alive" + "\n" + "Msg: " + "Resurrection" + "\n" +"@所有人"
			webhook(CONFIG.Setconf.Qy_rebootKey, infos)
			delete(server_diable_map , ip)
		}
	servermap [ip] = status
	ch <- struct{}{}
	}()
	select {
	case <-ch:
	case <-time.After(time.Second * time.Duration(CONFIG.Setconf.CheckserverTimeout)):
		fmt.Println("apiserver can't conection to ",fromip, "in this checktime,wait for next")
		if XStartid2 == 0 {
			server_diable_map = make(map[string]string)
			XStartid2 = 1
		}
		v , ok := servermap [ fromip]
		if (ok) && v == "disable" {
			_,ok := server_diable_map [fromip]
			if (ok){

			}
		}else  {
			servermap[fromip] = "disable"
			infos := "IP: " + fromip + "\n" + "Status: " + "Disable" + "\n" + "Msg: " + "agent is disable,or This address no found"
			webhook(CONFIG.Setconf.Qy_rebootKey, infos)
			_,ok := server_diable_map [fromip]
			if (ok){
				fmt.Println(fromip,"已在黑名单队列中")
			}else {
				server_diable_map [fromip] = "dis"
				fmt.Println(fromip,"<- AddMap ")
				go delmap(fromip)
			}
		}
	}
}

func delmap(name string){
	fmt.Println("will del",name, "in ",CONFIG.Setconf.BlackTime," Min")
	time.Sleep(time.Minute * time.Duration(CONFIG.Setconf.BlackTime))
	delete(server_diable_map , name)
	servermap[name] = "recheck"
	fmt.Println(name," --> be white")
}

func delnode(c *gin.Context){
	name := c.PostForm("ip")
	delete(servermap , name)
	var data string
	for k,_ := range  servermap{
		data = k + "\n" + data
	}
	writefile_server(CONFIG.Setconf.Ip_file,data)
	_,ok := servermap [name]
	if !(ok){
		c.JSON(200,gin.H{
			"err" : 1,
			"msg": "success",
		})
	}else {
		c.JSON(200,gin.H{
			"err" : 1,
			"msg" : "no found",
		})
	}
}


var XStartid int
var XStartid2 int
func Check_server(ipfile string){
	fmt.Println("CheckTime: ",CONFIG.Setconf.CheckserverTime)

	for {
		file, err := os.Open(ipfile)
		if err != nil {
			log.Fatalf("Error when opening file: %s", err)
		}
		fileScanner := bufio.NewScanner(file)
		for fileScanner.Scan(){
			if len(fileScanner.Text()) ==  0{
				continue
			}
		     go goruncheck(fileScanner.Text())
		}
     time.Sleep(time.Second * time.Duration(CONFIG.Setconf.CheckserverTime))
	}

}

type rehostinfos struct {
	Errmsg string `json:"errmsg"`

}

type cpunameinfo struct {
	Core    int    `json:"core"`
	Cpuname string `json:"cpuname"`
}


type hostinfos struct {
	Hostname string `json:"hostname"`
	Uptime int `json:"uptime"`
	BootTime int `json:"bootTime"`
	Procs int `json:"procs"`
	Os string `json:"os"`
	Platform string `json:"platform"`
	PlatformFamily string `json:"platformFamily"`
	PlatformVersion string `json:"platformVersion"`
	KernelVersion string `json:"kernelVersion"`
	KernelArch string `json:"kernelArch"`
	VirtualizationSystem string `json:"virtualizationSystem"`
	VirtualizationRole string `json:"virtualizationRole"`
	Hostid string `json:"hostid"`
}

func cmdbupdate(c *gin.Context){
	fmt.Println("begin start make cmdb")
	cmdb(CONFIG.Setconf.Ip_file)
}

var XStartid3 int
func cmdb(ipfile string){
	file, err := os.Open(ipfile)
	if err != nil {
		log.Fatalf("Error when opening file: %s", err)
	}
	fileScanner := bufio.NewScanner(file)
	for fileScanner.Scan(){
		if fileScanner.Text() == ""{
			continue
		}
		go makecmdb(fileScanner.Text())
	}
}

func delcmdb_node(c *gin.Context){
	ip := c.PostForm("ip")
	_, ok := cmdbmap[ip]
	if !(ok) {
		c.JSON(200,gin.H{
			"err" : 1,
			"msg" : "ip no found",
		})
	}else {
		delete(cmdbmap, ip)
		savecmdblist_local()
		c.JSON(200, gin.H{
			"err": 1,
			"msg": "success",
		})
	}
}

func makecmdb (fromip string){
	ch := make(chan struct{}, 1)
	go func() {
		if len(fromip) == 0 {
			os.Exit(0)
		}
		k , ok := cmdbmap [fromip]
		if (ok){
			lip := strings.Split(k, ";")
			hostname := lip[0]
			pla := lip[1]
			os := lip[2]
			kernel := lip[3]
			plaversion := lip[4]
			cpuname := lip[5]
			corestring := lip[6]
			mem := lip[7]
			statusx := servermap [fromip]
			if hostname != "none" || plaversion != "none"{
				//fmt.Println("配置已经存在 只更换机器状态")
				//localhost.localdomain.cluster.local;centos;linux;3.10.0-1160.53.1.el7.x86_64;7.9.2009;Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz;1;1.00;?
				datas := hostname + ";" + pla+ ";" + os + ";" + kernel + ";" +  plaversion + ";" + cpuname + ";"+ corestring + ";" + mem + ";"+ statusx
				cmdbmap [fromip] = datas
				ch <- struct{}{}
			}else  {
				url1 := "http://" + fromip + ":" + CONFIG.Setconf.Startport + "/gethostinfo"
				url2 := "http://" + fromip + ":" + CONFIG.Setconf.Startport + "/getcpuinfo"
				url3 := "http://" + fromip + ":" + CONFIG.Setconf.Startport + "/getmem"
				x := getinfo(url1)
				x2 := getinfo(url2)
				x3:= getinfo(url3)
				hostinfo := &hostinfos{}
				cpunameinfos := &cpunameinfo{}
				meminfo := &meminfos{}
				err := json.Unmarshal([]byte(x), hostinfo)
				if err != nil {
					fmt.Println("host err",err)
				}
				err = json.Unmarshal([]byte(x2), cpunameinfos)
				if err != nil {
					fmt.Println("Cpu err",err)
				}

				err = json.Unmarshal([]byte(x3),meminfo)
				if err != nil {
					fmt.Println("mem err",err)
				}

				mmme := meminfo.Total

				mmmegb := float64(mmme) / 1024 / 1024 / 1024

				memgbend := float64(mmmegb)

				mem1 := strconv.FormatFloat(float64(memgbend),'f',2,32)
				mem2 := mem1 + "GB"
				hostname := hostinfo.Hostname
				platform := hostinfo.Platform
				platformversion := hostinfo.PlatformVersion
				os := hostinfo.Os
				kernel := hostinfo.KernelVersion
				core := cpunameinfos.Core
				corestring := strconv.Itoa(core)
				cpuname := cpunameinfos.Cpuname
				v, _ := servermap[fromip]
				datas := hostname + ";" + platform + ";" + os + ";" + kernel + ";" + platformversion + ";" + cpuname + ";"+ corestring + ";" + mem2 + ";" + v
				cmdbmap[fromip] = datas
				fmt.Println(fromip, datas)
				ch <- struct{}{}
			}
		}else {
			url1 := "http://" + fromip + ":" + CONFIG.Setconf.Startport + "/gethostinfo"
			url2 := "http://" + fromip + ":" + CONFIG.Setconf.Startport + "/getcpuinfo"
			url3 := "http://" + fromip + ":" + CONFIG.Setconf.Startport + "/getmem"
			x := getinfo(url1)
			x2 := getinfo(url2)
			x3:= getinfo(url3)
			hostinfo := &hostinfos{}
			cpunameinfos := &cpunameinfo{}
			meminfo := &meminfos{}
			err := json.Unmarshal([]byte(x), hostinfo)
			if err != nil {
				fmt.Println("host err",err)
			}
			err = json.Unmarshal([]byte(x2), cpunameinfos)
			if err != nil {
				fmt.Println("Cpu err",err)
			}

			err = json.Unmarshal([]byte(x3),meminfo)
			if err != nil {
				fmt.Println("mem err",err)
			}

			mmme := meminfo.Total

			mmmegb := float64(mmme) / 1024 / 1024 / 1024

			memgbend := float64(mmmegb)
			mem1 := strconv.FormatFloat(float64(memgbend),'f',2,32)
			mem2 := mem1 + "GB"
			hostname := hostinfo.Hostname
			platform := hostinfo.Platform
			platformversion := hostinfo.PlatformVersion
			os := hostinfo.Os
			kernel := hostinfo.KernelVersion
			core := cpunameinfos.Core
			corestring := strconv.Itoa(core)
			cpuname := cpunameinfos.Cpuname
			v, _ := servermap[fromip]
			datas := hostname + ";" + platform + ";" + os + ";" + kernel + ";" + platformversion + ";" + cpuname + ";"+ corestring + ";" + mem2 + ";" + v
			cmdbmap[fromip] = datas
			fmt.Println(fromip, datas)
			ch <- struct{}{}
		}
	}()
	select {
	case <-ch:
	case <-time.After(time.Second *  time.Duration(CONFIG.Setconf.CheckserverTimeout)):
		v ,_ := servermap [fromip]
		x := "none"
		datas := x + ";" + x + ";" + x + ";" + x + ";"  + x + ";" + x + ";" +  x +";"+  x +";"+v
		cmdbmap [fromip] = datas
		fmt.Println(fromip,datas)
	}
	savecmdblist_local()
}

func corncmdbupdate(Sleep int){
	for{
		cmdb(CONFIG.Setconf.Ip_file)
		time.Sleep(time.Second *  time.Duration(Sleep))
	}
}

var listenmap_server map[string]string

func makelisten_server(c * gin.Context){
	ip := c.PostForm("ip")
	ltype := c.PostForm("ltype")
	lname := c.PostForm("lname")
	elseinfo:= c.PostForm("else")
	startcmd := c.PostForm("startcmd")
	timeStr:=time.Now().Format("2006-01-02 15:04:05")
	data := "waitcheck" + ";" + "grep " + lname + ";" + startcmd + ";" + elseinfo + ";" + ltype + ";" + ip + ";" + timeStr
	listenmap_server [elseinfo]  = data
    makelisten(ip,ltype,lname,elseinfo,startcmd)
	c.Redirect(http.StatusMovedPermanently, "/listenlist")
}

type BOrder struct{
	Errmsg string  `json:"errmsg"`
	Goods []BGood `json:"good"`
}

type BGood struct{
	GoodsName string `json:"goods_name"`
	GoodsIp string `json:"goods_ip"`
	Goodsstatus string `json:"goods_status"`
	Goodsinfo string `json:"goods_info"`
	Goodstime string `json:"goods_time"`
}

func listenlist_server(c *gin.Context){
	var BOrderInfo BOrder
	for k,x := range listenmap_server {
		lip := strings.Split(x,";")
		status := lip[0]
		findps := lip[1]
		restart := lip[2]
		elseinfo := lip[3]
		ltype := lip[4]
		ip := lip[5]
		updatetime := lip[6]
		listeninfo := "查找: " +findps + "," + "重启命令: "+ restart +"," + "备注: " + elseinfo +"," + "类型: " +ltype
		BOrderInfo.Errmsg = "009"
		BOrderInfo.Goods =append(BOrderInfo.Goods,BGood{GoodsName:k,GoodsIp:ip,Goodsstatus:status,Goodsinfo:listeninfo,Goodstime:updatetime})
	}
	c.JSON(200,BOrderInfo)
}


func dellisten_ip(url string,name string) {

	method := "GET"

	payload := &bytes.Buffer{}
	writer := multipart.NewWriter(payload)
	_ = writer.WriteField("name",name)
	err := writer.Close()
	if err != nil {
		fmt.Println(err)
		return
	}
	client := &http.Client {
	}
	req, err := http.NewRequest(method, url, payload)

	if err != nil {
		fmt.Println(err)
		return
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())
	res, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(body))
}


func dellisten_server(c * gin.Context){
	ip := c.PostForm("ip")
	name := c.PostForm("name")
	 _, ok := listenmap_server[name]
	 if !(ok) {
	 	c.JSON(200,gin.H{
	 		"err" : 10089,
	 		"msg" : "no found",
		})
	 }else {
		 url := "http://" + ip + ":" + CONFIG.Setconf.Startport + "/dellisten"
		 dellisten_ip(url, name)
		 delete(Blacklistenmap,name)
		 delete(listenmap_server, name)
		 //c.Redirect(http.StatusMovedPermanently, "/listenlist")
		 c.JSON(200,gin.H{
			 "err" : 10089,
			 "msg" : "success",
		 })
	 }
}

var serverlistenmap map[string]string

func makelisten(ip string,ltype string,lname string,elseinfo string,startcmd string)  {
	url :=  "http://"+ ip + ":" +CONFIG.Setconf.Startport + "/makelisten"
	method := "POST"
	payload := &bytes.Buffer{}
	writer := multipart.NewWriter(payload)
	_ = writer.WriteField("ltype", ltype)
	_ = writer.WriteField("lname", lname)
	_ = writer.WriteField("else", elseinfo)
	_ = writer.WriteField("startcmd", startcmd)
	err := writer.Close()
	if err != nil {
		fmt.Println(err)
		return
	}
	client := &http.Client {
	}
	req, err := http.NewRequest(method, url, payload)
	if err != nil {
		fmt.Println(err)
		return
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())
	res, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(body))
}


func listen_data_from_agent(c *gin.Context){
	ip := c.PostForm("ip")
	name := c.PostForm("name")
	status := c.PostForm("status")
	startcmd := c.PostForm("startcmd")
	elseinfo := c.PostForm("else")
	timeStr:=time.Now().Format("2006-01-02 15:04:05")
	data := status + ";" + "grep " + name + ";" + startcmd + ";" + elseinfo + ";" + "name" + ";" + ip + ";" + timeStr
	listenmap_server [elseinfo]  = data
}

var Blacklistenmap map[string]string
func check_listen_status_and_time_is_right(){
	for {
		for k, v := range listenmap_server {
			name := k
			info := strings.Split(v, ";")
			status := info[0]
			psname := info[1]
			ip := info[5]
			startcmd := info[2]
			lasttime := info[6]
			_,ok := Blacklistenmap[name]
			if status == "Bad" && !(ok) {
				data := "进程监控报警: " + "\n" + "来自: " + ip + "\n" + "备注: " + name + "\n" + "Status: " + status + "\n" + "进程检索名字: " + psname + "\n" + "预设启动命令:"+ startcmd +"\n" + "上次检查时间: " + lasttime + "\n" + "将开始持续监控此项直到恢复"
				fmt.Println(data)
				webhook(CONFIG.Setconf.Qy_rebootKey, data)
				Blacklistenmap [name] = "Disable"
				go balck_list(name)
			}
		}
		go checkListen_updatetime()
		time.Sleep(time.Second * time.Duration(CONFIG.Setconf.ChecklistenPs_time))
	}

}


func checkListen_updatetime() {

	for k, v := range listenmap_server {
		name := k
		_,ok := Blacklistenmap[name]
		if (ok) {
			continue
		}
		info := strings.Split(v, ";")
		status := info[0]
		psname := info[1]
		elseinfo := info[3]
		ip := info[5]
		startcmd := info[2]
		lasttime := info[6]
		var cstSh, _ = time.LoadLocation("Asia/Shanghai")
		t1 := time.Now().In(cstSh)
		fmt.Println(t1,"-",lasttime)
		loc, _ := time.LoadLocation("Local")
		Time, _:= time.ParseInLocation("2006-01-02 15:04:05",lasttime,loc)
		left := Time.Sub(t1)
		ends :=  left.Seconds()
		fmt.Println(ends)
		timeout := CONFIG.Setconf.ChecklistenTimeout * CONFIG.Setconf.ChecklistenPs_time * -1
		if ends < float64(timeout) {
			data2 := "Bad" + ";" + "grep " + name + ";" + startcmd + ";" + elseinfo + ";" + "name" + ";" + ip + ";" + lasttime
			listenmap_server [elseinfo]  = data2
			fmt.Println(name,status,psname,ip,startcmd)
			data := "进程监控报警: " + "\n" + "来自: " + ip + "\n" + "备注: " + name + "\n" + "Status: " + status + "\n" + "进程检索名字: " + psname + "\n" + "预设启动命令:"+ startcmd +"\n" + "上次检查时间: " + lasttime + "\n" + "系统检查到进程长时间没上报最新状态" + "\n" + "已自动扭转进程状态OK-->Bad,直到Agent上报最新状态"
			webhook(CONFIG.Setconf.Qy_rebootKey, data)
		}
	}
}

func balck_list(name string){
	startTime := time.Now()
	for {
		time.Sleep(time.Second * 20)
		v, _ := listenmap_server [name]
		info := strings.Split(v, ";")
		status := info[0]
		psname := info[1]
		ip := info[5]
		startcmd := info[2]
		lasttime := info[6]
		if status == "Bad" {
			data := "进程监控报警: " + "\n" + "来自: " + ip + "\n" + "备注: " + name + "\n" + "Status: " + status + "\n" + "进程检索名字: " + psname + "\n" + "预设启动命令:" + startcmd + "\n" + "上次检查时间: " + lasttime + "\n" + "将开始持续监控此项直到恢复"
			fmt.Println(data)
			webhook(CONFIG.Setconf.Qy_rebootKey, data)
		} else {
			elapsed := time.Since(startTime)
			strKm := fmt.Sprintf("%v", elapsed)
			data := "进程监控报警: " + "\n" + "来自: " + ip + "\n" + "备注: " + name + "\n" + "Status: " + status + "\n" + "进程检索名字: " + psname + "\n" + "预设启动命令:" + startcmd + "\n" + "上次检查时间: " + lasttime + "\n" + "进程已恢复,请及时确认" + "\n" + "此次持续时间: " + strKm
			fmt.Println(data)
			webhook(CONFIG.Setconf.Qy_rebootKey, data)
			delete(listenmap_server,name)
			runtime.Goexit()
		}
	}

}

func proxy_ip(c *gin.Context){
	ip := c.PostForm("ip")
	api := c.PostForm("api")
	url := "http://" + ip +":" +CONFIG.Setconf.Startport + "/"+ api
	c.Redirect(http.StatusMovedPermanently, url)
}

func sed(){ //参数
	var n string
	flag.StringVar(&n, "n", "", "new")
	var o string
	flag.StringVar(&o, "o", "8081", "old")
	var v string
	flag.StringVar(&v, "v", "", "version")
	var  show string
	flag.StringVar(&show, "show", "", "new")
	flag.Parse()

	if len(o) != 0 && len(n) != 0 {
		filename := "./templates/static/js/app.882927472b97c9c72b3e.js"
		f, err := ioutil.ReadFile(filename)
		if err != nil {
			fmt.Println("read fail", err)
			os.Exit(-1)
		}
		end := strings.ReplaceAll(string(f), o, n)
		writefile_server(filename, end)
		fmt.Println("更新完成")
		os.Exit(0)
	}

	if len(v) != 0  {
		fmt.Printf("Version Aegnt For Linux: %v And Apply to Centos,Ubuntu,Debian\n","LIP-0.2.07-Server")
		fmt.Printf("The code is written by: %v\n\n","Gs-engineer")
		os.Exit(0)
	}

	if len(show) != 0 {
		timeout := CONFIG.Setconf.ChecklistenTimeout * CONFIG.Setconf.ChecklistenPs_time * -1
		fmt.Println("代理检查时间: ",CONFIG.Setconf.CheckserverTime)
		fmt.Println("进程检查时间: ",CONFIG.Setconf.ChecklistenPs_time)
		fmt.Println("进程超时上报时间: ",timeout)
		fmt.Println("机器黑名单时间: ",CONFIG.Setconf.BlackTime)
		fmt.Println("Agent调用端口: ",CONFIG.Setconf.Apiport)
		fmt.Println("Cpu mem 超限: ",CONFIG.Setconf.Ccpu,CONFIG.Setconf.Cmem)
		fmt.Println("IP源文件: ",CONFIG.Setconf.Ip_file)
		fmt.Println("Ansible代理",CONFIG.Setconf.Ansible_mod)
		os.Exit(0)
	}


}



func proxytoansible(c *gin.Context){
	if CONFIG.Setconf.Ansible_mod == "yes" {
		url := "http://" + CONFIG.Setconf.Ansible_api + "/index"
		fmt.Println("proxy to --> ", url)
		c.Redirect(http.StatusMovedPermanently, url)
	}else {
		c.JSON(200,gin.H{
			"err" : 100901,
			"msg" : "Ansible模块或被设置禁止代理",
		})
	}
}

func Jiami(hexKey, raw string) (string, error) {
	key, err := hex.DecodeString(hexKey)
	if err != nil {
		return "", err
	}
	out, err := sm4.Sm4Ecb(key, []byte(raw), true)
	if err != nil {
		return "", err
	}
 return base64.StdEncoding.EncodeToString(out), nil
}


func Jiemi(hexKey, base64Raw string) (string, error) {
	if base64Raw == "" {
		return "", nil
	}

	key, err := hex.DecodeString(hexKey)

	if err != nil {
		return "", err
	}

	raw, err := base64.StdEncoding.DecodeString(base64Raw)

	if err != nil {
		return "", err
	}

	out, err := sm4.Sm4Ecb(key, raw, false)
	if err != nil {
		return "", err
	}
	return string(out), nil

}






//func showconf(){
//	var  show string
//	flag.StringVar(&show, "n", "", "new")
//	flag.Parse()
//	if len(show) != 0 {
//		timeout := CONFIG.Setconf.ChecklistenTimeout * CONFIG.Setconf.ChecklistenPs_time * -1
//		fmt.Println("代理检查时间: ",CONFIG.Setconf.CheckserverTime)
//		fmt.Println("进程检查时间: ",CONFIG.Setconf.ChecklistenPs_time)
//		fmt.Println("进程超时上报时间: ",timeout)
//		fmt.Println("机器黑名单时间: ",CONFIG.Setconf.BlackTime)
//		fmt.Println("Agent调用端口: ",CONFIG.Setconf.Apiport)
//		fmt.Println("Cpu mem 超限: ",CONFIG.Setconf.Ccpu,CONFIG.Setconf.Cmem)
//		fmt.Println("IP源文件: ",CONFIG.Setconf.Ip_file)
//		fmt.Println("Ansible代理",CONFIG.Setconf.Ansible_mod)
//	}
//
//}

func savecmdblist_local(){
	var data string
	//fmt.Println("保存本地文件")
	for k,v := range cmdbmap {
		//localhost.localdomain.cluster.local;centos;linux;3.10.0-1160.53.1.el7.x86_64;7.9.2009;Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz;1;OK
		data = k + "&" + v + "\n" + data
	}
	writefile_server("./data/cmdbremd",data)
}

func cmdblist_reback()string{
	fmt.Println(Green("Find local info fro server..."))
	file, err := os.Open("./data/cmdbremd")
	if err != nil {
		log.Fatalf("Error when opening file: %s", err)
	}
	fileScanner := bufio.NewScanner(file)
	for fileScanner.Scan(){
		if len(fileScanner.Text()) == 0 {
			continue
		}
		rdata := strings.Split(fileScanner.Text(),"&")
		ip := rdata[0]
		datas := rdata[1]
		cmdbmap [ip] = datas
	}
	return "ok"
}

const (
	textBlack = iota + 30
	textRed
	textGreen
	textYellow
	textBlue
	textPurple
	textCyan
	textWhite
)

func Red(str string) string {
	return textColor(textRed, str)
}
func Yellow(str string) string {
	return textColor(textYellow, str)
}
func Green(str string) string {
	return textColor(textGreen, str)
}



func textColor(color int, str string) string {
	return fmt.Sprintf("\x1b[0;%dm%s\x1b[0m", color, str)
}

func addnode_func(c *gin.Context){
	ip := c.PostForm("ip")
    addnode(ip)
	c.JSON(200,gin.H{
		"code" : "009",
		"msg": "success",
	})
}

func addnode(ip string)string{
	data := Read_file(CONFIG.Setconf.Ip_file)
	dataa := data + "\n" +ip
	writefile_server(CONFIG.Setconf.Ip_file,dataa)
	return dataa
}

func  uploadfile(c *gin.Context)  {
		file, filename, err := c.Request.FormFile("file")
		key := c.PostForm("ckey")
		if key != CONFIG.Setconf.ConectKey {
			c.JSON(http.StatusBadRequest, gin.H{"msg": "key not right"})
		}
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"msg": "file falied"})
			return
		}

		content, err := ioutil.ReadAll(file)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"msg": "read file err"})
			return
		}
		savename := "data/playbook/datas/" + filename.Filename
		writefile_server(savename,string(content))
		c.JSON(http.StatusOK, gin.H{"msg": "success"})
}


func getreplayfile_fromoneip(c *gin.Context){
	ip := c.PostForm("ip")
	url := "http://" + ip +":" +CONFIG.Setconf.Startport + "/"+ "userreplay"
	c.Redirect(http.StatusMovedPermanently, url)
}

func downloadreplayfile_fromoneip(c *gin.Context){
	ip := c.PostForm("ip")
	filename := c.PostForm("filename")
	url := "http://" + ip +":" +CONFIG.Setconf.Startport + "/"+ "download" + "?filename=" + filename
	c.Redirect(http.StatusMovedPermanently, url)
}

func lrangeshell(c *gin.Context){
	ckey := c.PostForm("ckey")
	shell := c.PostForm("shell")
	ip := c.PostForm("ip")
	if ckey != CONFIG.Setconf.ConectKey{
		c.JSON(200,gin.H{
			"code" : 10098,
			"msg" : "key not right",
		})

	}else {
	url := "http://" + ip +":" +CONFIG.Setconf.Startport + "/"+ "shellrunbyquery" + "?shell=" + shell
	c.Redirect(http.StatusMovedPermanently, url)
	}
}

type greoup struct{
	Errmsg string  `json:"errmsg"`
	Goods []Goodlist `json:"good"`
}

type Goodlist struct{
	Goodstag string `json:"goods_tag"`
	Goodsgroupname string `json:"goods_groupname"`
}

func readgroupincache(){
	for {
		file, err := os.Open("./data/selectgroup")
		if err != nil {
			log.Fatalf("Error when opening file: %s", err)
		}
		fileScanner := bufio.NewScanner(file)
		for fileScanner.Scan() {
			if len(fileScanner.Text()) == 0 {
				continue
			}
			rdata := strings.Split(fileScanner.Text(), ";")
			tag := rdata[0]
			groupname := rdata[1]
			groupmap[groupname] = tag
		}

		time.Sleep(time.Second * 10)
	}
}


func grouplist(c *gin.Context){
	var groups greoup

	for k,v := range groupmap{
			groups.Errmsg = "009"
			groups.Goods =append(groups.Goods,Goodlist{Goodstag: v,Goodsgroupname: k})
	}
	c.JSON(200,groups)
}


func nodegroup(c *gin.Context){
	ckey := c.PostForm("ckey")
	ip := c.PostForm("ip")

	if ckey	 != CONFIG.Setconf.ConectKey {
		return
	}
	file, err := os.Open("./data/nodegroup")
	if err != nil {
		log.Fatalf("Error when opening file: %s", err)
	}
	fileScanner := bufio.NewScanner(file)
	var tag int
	for fileScanner.Scan(){
		if len(fileScanner.Text()) == 0 {
			continue
		}
		rdata := strings.Split(fileScanner.Text(),";")
		if ip == rdata[0]{
			c.JSON(200,gin.H{
				"code" : 10099,
				"ip" : ip,
				"group": rdata[1],
			})
			tag = 2
		}
	}
	if tag != 2 {
		c.JSON(200,gin.H{
			"code" : 10099,
			"ip" : ip,
			"group": "no found in list",
		})
	}

}

type groupfornodejson struct{
	Errmsg string  `json:"errmsg"`
	Goods []Goodlistfornode `json:"good"`
}

type Goodlistfornode struct{
	Goodsip string `json:"goods_ip"`
	Goodsgroupname string `json:"goods_groupname"`
}

func groupfornode(c *gin.Context){

	var groupfornodes  groupfornodejson

	ckey := c.PostForm("ckey")
	group	 := c.PostForm("group")

	if ckey	 != CONFIG.Setconf.ConectKey {
		return
	}
	file, err := os.Open("./data/nodegroup")
	if err != nil {
		log.Fatalf("Error when opening file: %s", err)
	}
	fileScanner := bufio.NewScanner(file)
	groupfornodes.Errmsg = "10091"
	for fileScanner.Scan(){
		if len(fileScanner.Text()) == 0 {
			continue
		}
		rdata := strings.Split(fileScanner.Text(),";")
		if group == rdata[1]{
			groupfornodes.Goods =append(groupfornodes.Goods,Goodlistfornode{Goodsip: rdata[0],Goodsgroupname: group})
		}
	}
	c.JSON(200,groupfornodes)
}

func readnodegroupintocache(){
		file, err := os.Open("./data/nodegroup")
		if err != nil {
			log.Fatalf("Error when opening file: %s", err)
		}
		fileScanner := bufio.NewScanner(file)
		for fileScanner.Scan() {
			if len(fileScanner.Text()) == 0 {
				continue
			}
			rdata := strings.Split(fileScanner.Text(), ";")
			ip := rdata[0]
			group := rdata[1]
			nodegroupmap [ip] = group
		}
}



func addnodeintogroup(c *gin.Context){
	ip :=    c.PostForm("ip")
	group := c.PostForm("group")
	ckey :=  c.PostForm("ckey")
	if ckey	 != CONFIG.Setconf.ConectKey {
		return
	}
	_,ok := groupmap [group]
	if !(ok){
		c.JSON(200,gin.H{
			"code" : 10010,
			"group": "no found Group: " + group + " in system",
		})
	}else {
		_, ok = nodegroupmap[ip]
		if !(ok) {
			nodegroupmap[ip] = group
			var datainfo string
			for k, v := range nodegroupmap {
				datainfo = k + ";" + v +   "\n" +datainfo
				writefile_server("data/nodegroup", datainfo)
			}
			c.JSON(200, gin.H{
				"code":  10010,
				"group": "success",
			})
		}else {
			c.JSON(200, gin.H{
				"code":  10010,
				"group": "failed ip:" + ip + " already in other Group",
			})
		}
	}
}

func delnodeintogroup(c *gin.Context){
	ip :=    c.PostForm("ip")
	group := c.PostForm("group")
	ckey :=  c.PostForm("ckey")
	if ckey	 != CONFIG.Setconf.ConectKey {
		return
	}
	_,ok := groupmap [group]
	if !(ok){
		c.JSON(200,gin.H{
			"code" : 10010,
			"group": "no found group: " + group + " in system",
		})
	}else {
		_, ok = nodegroupmap[ip]
		if (ok) {
			delete(nodegroupmap,ip)
			var datainfo string
			for k, v := range nodegroupmap {
				datainfo = k + ";" + v +   "\n" +datainfo
				writefile_server("data/nodegroup", datainfo)
			}
			c.JSON(200, gin.H{
				"code":  10010,
				"group": "success",
			})
		}else {
			c.JSON(200, gin.H{
				"code":  10010,
				"group": "failed Can't find ip:" + ip + " in this Group",
			})
		}
	}
}



var db *sql.DB
func initDB() (err error) {
	// DSN:Data Source Name
	fmt.Println(CONFIG.Setconf.User,CONFIG.Setconf.Passwd,CONFIG.Setconf.Dbaddress)
	dbinfo := CONFIG.Setconf.User + ":" + CONFIG.Setconf.Passwd + "@tcp(" + CONFIG.Setconf.Dbaddress + ")/cmdb_disk"
	dsn := dbinfo
	// 不会校验账号密码是否正确
	db, err = sql.Open("mysql", dsn)
	if err != nil {
		return err
	}
	// 尝试与数据库建立连接（校验dsn是否正确）
	err = db.Ping()
	if err != nil {
		return err
	}
	return nil
}

var groupmap map[string]string
var nodegroupmap map[string]string
func main(){
	InitConfigFromIni() //导入配置文件
	err := initDB()
	if err != nil {
		fmt.Printf("init db failed,err:%v\n", err)
		os.Exit(-1)
	}
	sed() //一些参数 和端口替换

	servermap = make(map[string]string) //node
	listenmap_server = make(map[string]string) //listen map_server
	serverlistenmap  = make(map[string]string) //
	Blacklistenmap   = make(map[string]string)
	checking   = make(map[string]string)
	cmdbmap = make(map[string]string)
	groupmap = make(map[string]string)
	nodegroupmap = make(map[string]string)

    fmt.Println(Red(". Api Server Starting......"))
	go Check_server(CONFIG.Setconf.Ip_file) //启动定时检查机器状态
	go readgroupincache() //组列表缓存
	readnodegroupintocache() //ip回位组
	fmt.Println(Red(". Load Conf......"))
	checkstatus := cmdblist_reback() //恢复cmdb
	if checkstatus != "ok"{
		fmt.Println(Red("Run api Error: may hanped by cmdbmod "))
		os.Exit(0)
	}else {
		fmt.Println(Green("Loacl file reback finsh"))
	}
	time.Sleep(time.Second * 2)
	fmt.Println(Red(". Initialization......"))
	go check_listen_status_and_time_is_right() //检查进程状态
	fmt.Println(Yellow("Wait for apiserver full start....."))
	time.Sleep(time.Second * 3)
	go corncmdbupdate(CONFIG.Setconf.CorncmdbupdateTime) //定时更新机器cmdb
	start1 := 1
	str := "."
	str2 := "."
	for start1 < 5{
		str = str2 + str
		fmt.Printf(Green(str))
		start1++
		time.Sleep(time.Second)
	}
	go listendisk() //定时收集磁盘信息
	fmt.Printf(Green("√"))
	time.Sleep(time.Second * 2)
	fmt.Println(Green("Start ok √"))
	go checkdiskfrommysql() //检查磁盘


    server := gin.Default()
	server.SetFuncMap(template.FuncMap{
		"safe": func(str string) template.HTML{
			return template.HTML(str)
		},
		"safe2": func(str string) template.HTML{
			return template.HTML(str)
		},
	})


	server.LoadHTMLGlob(TemplateFiles)
	server.Static("/static", StaticFiles)
	server.Use(JSONAppErrorReporter())
	server.Use(CORSMiddleware())
	server.POST("/login_get",func (c *gin.Context){
		uname := c.PostForm("username")
		up := c.PostForm("passwd")
		f, err := ioutil.ReadFile("./User.admin")
		if err != nil {
			fmt.Println("read fail", err)
		}
		logininfo := "u:" + uname + "," + "p:" + up
		Index := strings.Index(string(f),logininfo)
		if Index != -1 {
			fmt.Println(logininfo,"login")
			c.Next()
		}else {
			fmt.Println(logininfo,"login err")
			c.HTML(http.StatusOK, "err.html", nil)
			c.Abort()
		}
	},func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", nil)
	})
	server.GET("/w",func (c *gin.Context){
		c.HTML(http.StatusOK, "logins.html", nil)
	})
	server.GET("/ws", views.ShellWs)



    //ops
   server.POST("/getnode",getnode)  //获取单个node
   server.POST("/getallnode",getallnode) //获取所有node
   server.POST("/delnode",delnode) //删除node
   server.POST("/cmdbupdate",cmdbupdate) //手动触发更新cmdb
   server.POST("/cmdblist",cmdblist) //获取node list
   server.POST("/makelisten",makelisten_server) //listen ps
   server.POST("/dellisten",dellisten_server)
    server.GET("/listenlist",listenlist_server)
    server.POST("/listen_data_from_agent",listen_data_from_agent) //agent上报状态
   server.POST("/proxy",proxy_ip)
	server.GET("/ansible",proxytoansible) //ansible代理
    server.POST("/addnode",addnode_func)
    server.POST("/delcmdb",delcmdb_node)
	server.POST("/uploadfile",uploadfile)
    server.POST("/getreplaylog",getreplayfile_fromoneip)
    server.POST("/downloadreplaylog",downloadreplayfile_fromoneip)
    server.POST("/lrangeshell",lrangeshell)
    server.GET("/grouplist",grouplist)
    server.GET("/nodegroup",nodegroup)
    server.GET("/groupfornode",groupfornode)
    server.GET("/addnodeintogroup",addnodeintogroup)
    server.GET("/delnodefromgroup",delnodeintogroup)
    server.GET("/api",func(c *gin.Context){
    	c.JSON(200,gin.H{
    		"err" : 520,
    		"msg" : "success",
		})
	})
    server.GET("/test",func (c *gin.Context){
    	c.HTML(200,"newcss.html",nil)
	})
	fmt.Println(Green("Start ok,Look like all service is ok"))
    runip := CONFIG.Setconf.Apiserver + ":" + CONFIG.Setconf.Apiport
   server.Run(runip)

}





func Read_file(filname string)  (string){
	f, err := ioutil.ReadFile(filname)
	if err != nil {
		fmt.Println("read fail", err)
	}
	return string(f)
}


//writefile_server full
func writefile_server(filename string,nei string) error{
	fileName := filename
	f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
	if err != nil {
		fmt.Println("file create failed. err: " + err.Error())
	} else {

		content := nei
		n, _ := f.Seek(0, os.SEEK_END)
		_, err = f.WriteAt([]byte(content), n)

		defer f.Close()
	}
	return err
}


